package com.lzyyj.gmis.base.dao;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.persistence.Query;

import com.lzyyj.common.Page;

/** 
 * 针对单个Entity对象的操作定义.不依赖于具体ORM实现方案. 
 * 
 * @author lzyyj 
 * 
 */ 
public interface IBaseDao<T,PK extends Serializable>{ 
	
	public Class<T> getEntityClass();
	
	/**
	 * jpql 条件KEY
	 */
	public final String JPQL_CONDITION = "jpqlCondition";
	
	/**
	 * 条件Map中 jpql 的  KEY
	 */
	public final String JPQL = "jpql";
	
	/**
	 * 条件Map中 jpql 的  KEY
	 */
	public final String VALUES = "values";
	
	/**
	 * 条件Map中 jpql 的  KEY
	 */
	public final String EXAMPLE_PROPERTIES = "exampleProperties";
	
	/**
	 * 条件Map中 jpql 的  KEY
	 */
	public final String PROPERTY_LIST = "propertyList";

	/**
	 * 对以前还未曾保存过的实体进行初始保存。所有后续的持久化操作应该使用 #update()
	 * 方法。 This operation must be performed within the a database
	 * transaction context for the entity's data to be permanently saved to the
	 * persistence store, i.e., database. This method uses the
	 * {@link javax.persistence.EntityManager#persist(Object)
	 * EntityManager#persist} operation.
	 * <p>
	 * User-managed Spring transaction example:
	 * 
	 * <pre>
	 * TransactionStatus txn = txManager
	 * 		.getTransaction(new DefaultTransactionDefinition());
	 * PersonDAO.save(entity);
	 * txManager.commit(txn);
	 * </pre>
	 * 
	 * @see <a href =
	 *      "http://www.myeclipseide.com/documentation/quickstarts/jpaspring#containermanaged">Spring
	 *      container-managed transaction examples</a>
	 * @param entity
	 *            Person entity to persist
	 * @throws Exception 
	 * @throws RuntimeException
	 *             when the operation fails
	 */
	public T save(T entity) throws Exception;

	public T save(T entity, String propertyList) throws Exception;
	
	/** 
	 * 删除对象. 
	 *  
	 * @see HibernateGenericDao#deleteById(Class,Serializable) 
	 */ 
	void delete(Object obj) throws Exception;

	/** 
	 * 删除对象. 
	 *  
	 * @see HibernateGenericDao#deleteById(Class,Serializable) 
	 */ 
	public void deleteById(PK id);

	/** 
	 * 批量删除对象. 
	 *  
	 * @see HibernateGenericDao#deleteById(Class,Serializable) 
	 */ 
	public void deleteByIds(PK[] ids);

	public T update(T entity) throws Exception;

	public T update(T entity, String propertyList) throws Exception;

	public T saveOrUpdate(T entity);

	/**
	 * 对符合条件的对象执行指定的更新命令
	 * @param jpql
	 */
	public void executeUpdate(String jpql, Object... values);

	/**
	 * 获得新实例
	 * @return
	 */
	public T getNew();

	public T get(T entity);

	public T get(T entity, String propertyList);

	/** 
     * 根据ID获取对象. 如果对象不存在，返回空. 
     * @see HibernateGenericDao#getPK(PK) 
     */ 
    public T getById(PK id); 

	/** 
     * 根据ID获取对象. 如果对象不存在，返回空. 
	 * @throws Exception 
     * @see HibernateGenericDao#getPK(PK) 
     */ 
    public T getById(PK id, String propertyList) throws Exception; 
	
	/** 
     * 根据ID获取对象. 实际调用Hibernate的session.load()方法返回实体或其proxy对象. 如果对象不存在，抛出异常. 
	 * @throws Exception 
     * @see HibernateGenericDao#getPK(PK) 
     */ 
    public T load(PK id) throws Exception; 

	/**
	 * 获得所有记录总数
	 * @return
	 */
	public long getAllCount();

	/**
	 * 查询符合条件的记录个数
	 * @param condition
	 * @return
	 */
	public long getCount(Map<String,Object> condition);

	/**
	 * 查询符合条件的记录个数
	 * @param condition
	 * @return
	 */
	public long getCount(String condition);

	/** 
	 * 判断对象某些属性的值在数据库中唯一. 
	 *  
	 * @param uniquePropertyNames 
	 *            在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password" 
	 * @see HibernateGenericDao#isUnique(Class,Object,String) 
	 */ 
	public boolean isUnique(T entity, String uniquePropertyNames);

	/** 
	 * 根据属性名和属性值查询单个对象. 
	 *  
	 * @return 符合条件的唯一对象 or null 
	 * @see HibernateGenericDao#findUniqueBy(String,Object) 
	 */ 
	public T findUniqueBy(String propertyName, Object value);

	/** 
	 * 根据属性列表和属性值列表查询单个对象. 
	 *  
	 * @return 符合条件的唯一对象 or null 
	 * @see HibernateGenericDao#findUniqueBy(String,Object) 
	 */ 
	public T findUniqueBy(String propertyList, Object... values);

	/** 
     * 获取全部对象 
     *  
     * @see HibernateGenericDao#findAll() 
     */ 
    public List<T> findAll();
    
    /** 
	 * 按指定顺序，分页获取全部对象. 
	 *  
	 * @see HibernateGenericDao#findAll(String,boolean) 
	 */ 
	public List<T> findAll(String orderBy, long... firstAndMaxResults);

	public List<T> findAll(String fieldList, String orderFields, long... rowStartIdxAndCount);

	/**
     * 以参照实例为模板进行查找
     * @param instance
     * @return
	 * @throws Exception 
     */
	public List<T> findByExample(T instance, long... firstAndMaxResults) throws Exception;
	
    /** 
     * 返回与给定示例的指定的属性相符的对象列表
     * 
     * @param propertyNames 在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password" 
     * @throws Exception 
     */ 
    public List<T> findByExample(T entity, String propertyList, String orderBy, long... firstAndMaxResults) throws Exception;
	
    /** 
     * 返回与给定示例的指定的属性相符的对象列表
     * 
     * @param propertyNames 在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password" 
     * @throws Exception 
     */ 
    public List<T> findByExample(T entity, String propertyList, String orderBy, String propertyList2, long... firstAndMaxResults) throws Exception;
    
    /** 
	 * 根据属性名和属性值查询对象,带排序参数. 
	 *  
	 * @return 符合条件的对象列表 
     * @throws Exception 
	 * @see HibernateGenericDao#findBy(Class,String,Object,String,boolean) 
	 */ 
	public List<T> findByProperty(String propertyName, Object value, String orderBy, String propertyList) throws Exception;

    /** 
	 * 根据属性名和属性值查询对象,带排序参数. 
	 *  
	 * @return 符合条件的对象列表 
     * @throws Exception 
	 * @see HibernateGenericDao#findBy(Class,String,Object,String,boolean) 
	 */ 
	public List<T> findByProperty(String propertyName, Object value, String orderBy, long... firstAndMaxResults) throws Exception;

    /** 
	 * 根据属性名和属性值查询对象,带排序参数. 
	 *  
	 * @return 符合条件的对象列表 
	 * @see HibernateGenericDao#findBy(Class,String,Object,String,boolean) 
	 */ 
	public Page<T> findByProperty(Page<T> page, String propertyName, Object value);

	/**
	 * 
	 * 根据属性名和属性值查询对象,带排序参数. 
	 *  
	 * @return 符合条件的对象列表 
	 * @param entityClass
	 * @param propertyName
	 * @param value
	 * @param orderBy
	 * @param firstAndMaxResults
	 * @return
	 * @throws Exception 
	 */
	public List<T> findByProperty(String propertyName, Object value, String orderBy, String propertyList, long... firstAndMaxResults) throws Exception;

	/**
	 * 
	 * 根据属性名和属性值查询对象,带排序参数. 
	 *  
	 * @return 符合条件的对象列表 
	 * @param entityClass
	 * @param propertyName
	 * @param value
	 * @param orderBy
	 * @param firstAndMaxResults
	 * @return
	 * @throws Exception 
	 */
	public <E> List<E> findByProperty(Class<E> entityClass, String propertyName, Object value, String orderBy, long... firstAndMaxResults) throws Exception;

	/**
	 * 
	 * 根据属性名和属性值查询对象,带排序参数. 
	 *  
	 * @return 符合条件的对象列表 
	 * @param entityClass
	 * @param propertyName
	 * @param value
	 * @param orderBy
	 * @param firstAndMaxResults
	 * @return
	 * @throws Exception 
	 */
	public <E> List<E> findByProperty(Class<E> entityClass, String propertyName, Object value, String orderBy, String propertyList, long... firstAndMaxResults) throws Exception;

	/** 
     * 根据hql查询,直接使用HibernateTemplate的find函数. 
     * 
     * @param values 可变参数,见{@link #getQuery(String,Object...)} 
     */ 
	public List<T> find(String hql, Object... values);

	public Page<T> find(Page<T> page);

	/**
	 * 分段查询符合条件的记录
	 * @param condition
	 * @param startIndex
	 * @param maxCount
	 * @param orderBy
	 * @return
	 */
	public List<T> findBy(String condition,long startIndex,long maxCount,String orderBy);

	/** 
	 * 获取Entity对象的主键名. 
	 */ 
	public String getPKName();

	public void flush();

	public void clear();

	public long getCount(Page<T> page);

	public long getCountByProperty(String propertyName, Object value, String orderBy);

	public void merge(T entity);

	public PK getPK(T entity) throws NoSuchMethodException, IllegalAccessException,
			InvocationTargetException;
	
	public Query createQuery(String hql, Object... values);
	
	/**
	 * 执行无返回值的存储过程
	 * @param procName sql语句
	 * @param value	值
	 * @throws SQLException
	 */
	public void callProc(String procName, Object... values) throws SQLException;

	/**
	 * 获得实体类的属性列表
	 * @return
	 */
	public String getPropertyList();

	/**
	 * 获得实体类的属性列表
	 * @return
	 */
	public String[] getProperties();

	/**
	 *  检查该类型是否为可持久化类
	 * @param clazz
	 * @return
	 */
	public boolean isEntity(Class<?> clazz);

	/**
	 * 获得指定类型对象的持久化对象
	 * @param value
	 * @return
	 */
	public Object getByClass(Object value);

	/**
	 * 获得持久化实体名列表
	 * @return
	 */
	public List<Map<String, Object>> getEntityNameList();

	/**
	 * 获取指定实体的属性列表
	 * @param entityClass
	 * @return
	 */
	public String[] getProperties(Class<?> entityClass);

	/**
	 * 获取各外键实体对象列表
	 * @param objectClass 主键实体类型
	 * @param aliasNames 别名列表，逗号分隔
	 * @param entityPo	持久化实体对象	
	 * @return	
	 * @throws ClassNotFoundException
	 * @throws Exception 
	 */
	public Map<String, List<? extends Object>> getRefListMap(Class<?> objectClass, String aliasNames, Object entityPo) throws ClassNotFoundException, Exception;

	/**
	 * 替换外键引用，即更换外键对象引用方
	 * @param objectClass
	 * @param aliasNames
	 * @param srcId
	 * @param tarId
	 * @return 成功替换外键类型数
	 * @throws Exception
	 */
	public int replaceRef(Class<?> objectClass, String aliasNames, Serializable srcId, Serializable tarId) throws Exception;
	
	/**
	 * 获取处理指定实体类的 dao
	 * @param clazz1
	 * @return
	 */
	public <T1, PK1 extends Serializable> IBaseDao<T1, PK1> getBaseDao(Class<T1> clazz1);
	   
    /**
     * 获得指定对象在指定查询条件下的位置序号，0算起
     * @param entity
     * @param criteria
     * @param orderBy
     * @return
     */
    public long getIndex(T focus, Page<T> page);

	/**
	 * 取得指定实体类的主键属性名,辅助函数.
	 * @return
	 */
	public String getPkNameByEntityClass(Class<?> entityClass);

	/**
	 * 判断指定属性是否是持久化属性
	 * @param propertyName
	 * @return
	 */
	public boolean isPersistentProperty(String propertyName);

	/**
	 * 判断指定属性是否是持久化属性
	 * @param propertyName
	 * @return
	 */
	public <E> boolean isPersistentProperty(Class<E> clazz, String propertyName);

	public Map<PK, T> getInherentEntities();

	/**
	 * 按属性列表要求加载持久化对象的属性
	 * @param entityPo
	 * @param entityClass
	 * @param propertyList
	 * @throws Exception 
	 */
	public Map<Class<?>, Map<Serializable, Object>> loadProperties(Object entityPo, Class<?> entityClass, String propertyList, Map<Class<?>, Map<Serializable, Object>> propertyValueCache) throws Exception;

	/**
	 * 指定的实体属性是否非空
	 * @param entityClass
	 * @param propertyName
	 * @return
	 */
	public boolean isPropertyNonNull(Class<?> entityClass, String propertyName);

	/**
	 * 按属性列表要求加载持久化对象的属性
	 * @param entityPo
	 * @param entityClass
	 * @param propertyList
	 * @throws Exception 
	 */
	public <E> Map<Class<?>, Map<Serializable, Object>> loadProperties(Collection<E> list, Class<E> clazz, String propertyList, Map<Class<?>, Map<Serializable, Object>> propertyValueCache) throws Exception;

	/**
	 * 获取外键映射配置
	 * @return
	 */
	public Map<String, Class<?>> getForeignKeyMap();

}
